package teamBattle

import (
	"fmt"
	"sort"
	"time"

	"7qule.com/sd3/CrossServer/src/common/onlinelog"
	"7qule.com/sd3/CrossServer/src/common/systemConstant"
	"public.com/goutil/syncUtil"
)

// 队伍信息
type TeamInfo struct {
	// 战斗节点Id
	battleNodeId int32

	// 队长Id
	leader *TeamMember

	// 成员数据，key：成员显示序号(从1开始)
	memberData map[int32]*TeamMember

	// 队伍锁对象
	teamLocker *syncUtil.RWLocker

	// 队伍状态
	status TeamStatus

	// 创建时间
	createTime time.Time

	// 模块Id
	moduleId int32

	// 每个成员的翻牌奖励信息
	fanPaiInfo string

	// 最低战力要求
	minFap int64

	// 队伍宣言
	slogan string

	// 最后一次操作时间
	lastHandleTime time.Time

	// 已挑战次数
	battleCount int

	// 需要挑战的次数
	needBattleCount int

	// 是否能够在组队大厅展示（随机推荐队伍接口） 默认为true
	ifCanShow bool

	// 节点战力信息 本应为[]int64，现在是[]float64
	nodeFap interface{}

	// 是否自动准备，这个只是前端用于自动更改状态，我只是用来判断超时状态而已
	ifAutoReady bool

	// 队伍是否挂机
	isGuaji bool
}

// 队伍Id
func (this *TeamInfo) TeamId() string {
	return this.leader.PlayerId
}

// 队长
func (this *TeamInfo) Leader() *TeamMember {
	return this.leader
}

// 战斗节点Id
func (this *TeamInfo) BattleNodeId() int32 {
	return this.battleNodeId
}

// 设置战斗节点Id
func (this *TeamInfo) SetBattleNodeId(_battleNodeId int32) {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.battleNodeId = _battleNodeId
}

// 获取队伍成员的副本集合
// 返回值:
// map[string]*TeamMember: key:位置Id，
func (this *TeamInfo) MemberDataCopy() map[int32]*TeamMember {
	if isOk, prevStack, currStack := this.teamLocker.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.RUnlock()

	result := make(map[int32]*TeamMember, len(this.memberData))
	for key, val := range this.memberData {
		result[key] = val
	}

	return result
}

// 获取按照位置排序后的队伍成员信息
func (this *TeamInfo) MemberDataByPos() (result []*TeamMember) {
	if isOk, prevStack, currStack := this.teamLocker.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.RUnlock()

	posIdList := make([]int, 0, len(this.memberData))
	for key, _ := range this.memberData {
		posIdList = append(posIdList, int(key))
	}

	sort.Ints(posIdList)

	result = make([]*TeamMember, 0, len(this.memberData))
	for _, posId := range posIdList {
		result = append(result, this.memberData[int32(posId)])
	}

	return
}

// 成员数量
func (this *TeamInfo) MemberLen() int {
	if isOk, prevStack, currStack := this.teamLocker.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.RUnlock()

	return len(this.memberData)
}

// 获取成员对象
// playerId:玩家Id
// ifClone:是否返回拷贝对象
// 返回值:
// int32:成员位置Id
// *TeamMember:成员对象
// bool:是否存在对应成员
func (this *TeamInfo) GetMember(playerId string, ifClone bool) (int32, *TeamMember, bool) {
	if isOk, prevStack, currStack := this.teamLocker.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.RUnlock()

	for positionId, memberItem := range this.memberData {
		if memberItem.PlayerId == playerId {
			if ifClone {
				return positionId, memberItem.GetCopy(), true
			}

			return positionId, memberItem, true
		}
	}

	return -1, nil, false
}

// 获取成员对象
// positionId:位置Id
// ifClone:是否返回拷贝对象
// 返回值:
// *TeamMember:成员对象
// bool:是否存在对应成员对象
func (this *TeamInfo) GetMemberByPosId(positionId int32, ifClone bool) (*TeamMember, bool) {
	if isOk, prevStack, currStack := this.teamLocker.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.RUnlock()

	result, isExist := this.memberData[positionId]
	if isExist == false {
		return nil, false
	}

	return result, true
}

// 更改队伍状态
func (this *TeamInfo) SetStatus(targetStatus TeamStatus) bool {
	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	// 如果状态合法，则转换状态
	if CheckStatus(this.status, targetStatus) {
		this.status = targetStatus

		return true
	}

	return false
}

// 当前队伍状态
func (this *TeamInfo) Status() TeamStatus {
	return this.status
}

// 重置挑战数据
// _needBattleCount:需要挑战的次数
// ifNotResetReadyStatus:是否不需要重置所有玩家的准备状态
// 返回值:
// error:错误信息
func (this *TeamInfo) ResetBattleInfo(_needBattleCount int, ifNotResetReadyStatus bool) error {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	if this.status != TeamingStatus {
		return fmt.Errorf("队伍不是组队状态，无法设置挑战次数")
	}

	this.needBattleCount = _needBattleCount
	this.battleCount = 0

	if ifNotResetReadyStatus == false {
		for _, item := range this.memberData {
			if item.IsPlayer {
				// 只重置真实玩家的状态
				item.ReadyStatus = ReadyStatus_Init
			}
		}
	}

	return nil
}

// 需要挑战的次数
func (this *TeamInfo) NeedBattleCount() int {
	return this.needBattleCount
}

// 完成一次挑战
func (this *TeamInfo) BattleOnce() {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	// 重置是否挑战
	for _, item := range this.memberData {
		if item.IsPlayer {
			// 只重置真实玩家的状态
			item.ReadyStatus = ReadyStatus_Init
		}
	}

	// 更新挑战次数
	this.battleCount++
}

// 获取挑战次数
func (this *TeamInfo) BattleCount() int {
	return this.battleCount
}

// 最后一次准备状态变更时间
func (this *TeamInfo) LastHandleTime() time.Time {
	return this.lastHandleTime
}

// 最后一次准备状态变更时间
func (this *TeamInfo) UpdateLastHandleTime() {
	this.lastHandleTime = time.Now().Local()
}

// 准备战斗
// playerId:成员Id
// isReady:是否准备好
// 返回值:
// map[string]ReadyStatusEnum:所有成员的准备情况
// error:错误信息
func (this *TeamInfo) ReadyForBattle(playerId string, isReady bool) (map[string]ReadyStatusEnum, error) {
	// 队长准备时，更改准备时间
	if this.Leader().PlayerId == playerId {
		this.UpdateLastHandleTime()
	}

	// 只有组队状态下才能准备
	_, memerberItem, exist := this.GetMember(playerId, false)
	if exist == false {
		return nil, fmt.Errorf("指定队伍成员不存在")
	}

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	if this.status != TeamingStatus {
		return nil, fmt.Errorf("只有组队状态才能进行准备操作")
	}

	// 设置为就绪状态
	if isReady {
		memerberItem.ReadyStatus = ReadyStatus_Ready
	} else {
		memerberItem.ReadyStatus = ReadyStatus_Cancel
	}

	// 组装返回数据
	readyResult := make(map[string]ReadyStatusEnum, len(this.memberData))
	for _, item := range this.memberData {
		readyResult[item.PlayerId] = item.ReadyStatus
	}

	return readyResult, nil
}

// 设置双倍令使用状态
// playerId:成员Id
// isUseDouble:是否使用双倍令
// 返回值:
// bool:是否设置成功
// error:错误信息
func (this *TeamInfo) SetIsUseDouble(playerId string, isUseDouble bool) (bool, error) {

	// 只有组队状态下才能修改双倍令
	_, memerberItem, exist := this.GetMember(playerId, false)
	if exist == false {
		return false, fmt.Errorf("指定队伍成员不存在")
	}

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	if this.status != TeamingStatus {
		return false, fmt.Errorf("只有组队状态才能进行使用双倍令操作")
	}

	memerberItem.IsUseDouble = isUseDouble

	return true, nil
}

// 添加成员
// memberItem:待添加的成员对象
// maxNum:包含队长在内的最大成员数
// 返回值:
// bool:是否成功添加（如果已经是成员，则也会返回true）
func (this *TeamInfo) AddMemeber(memberItem *TeamMember, maxNum int) bool {
	if _, _, isExist := this.GetMember(memberItem.PlayerId, false); isExist {
		return true
	}

	if this.MemberLen() >= maxNum {
		return false
	}

	if this.status != TeamingStatus {
		return false
	}

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	if len(this.memberData) >= maxNum {
		return false
	}

	if this.status != TeamingStatus {
		return false
	}

	// 加入成员
	posId := this.getUsableIndex()
	this.memberData[posId] = memberItem

	return true
}

// 移除成员
// playerId:成员Id
func (this *TeamInfo) RemoveMember(playerId string) error {
	if playerId == this.leader.PlayerId {
		return fmt.Errorf("队长不能移除")
	}

	if _, _, isExist := this.GetMember(playerId, false); isExist == false {
		return nil
	}

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	// 只有组队状态才能退出队伍
	if this.status != TeamingStatus {
		return fmt.Errorf("队伍状态不合法")
	}

	var memberPositionId int32 = -1
	for positionId, memberItem := range this.memberData {
		if memberItem.PlayerId == playerId {
			memberPositionId = positionId
		}
	}
	if memberPositionId < 0 {
		return nil
	}

	delete(this.memberData, memberPositionId)

	return nil
}

// 变更位置
// playerId:玩家Id
// targetPosId:目标位置(需要外部保证位置的合法性)
// 返回值:
// error:错误信息
func (this *TeamInfo) ChangePosition(playerId string, targetPosId int32) error {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	if this.Status() != TeamingStatus {
		return fmt.Errorf("不是组队状态")
	}

	var (
		nowPosId   int32       = -1
		memberInfo *TeamMember = nil
	)

	// 获取玩家当前所在位置
	for positionId, memberItem := range this.memberData {
		if memberItem.PlayerId == playerId {
			nowPosId = positionId
			memberInfo = memberItem
			break
		}
	}

	if memberInfo == nil {
		return fmt.Errorf("未找到目标玩家")
	}

	// 读取目标位置玩家
	tmpMember, isExist := this.memberData[targetPosId]
	if isExist {
		// 目标位置存在玩家，则交换位置
		this.memberData[targetPosId] = memberInfo
		this.memberData[nowPosId] = tmpMember
	} else {
		// 换到指定位置，并删除之前位置的项
		this.memberData[targetPosId] = memberInfo
		delete(this.memberData, nowPosId)
	}

	return nil
}

// 获取一个可用的位置序号(从1开始)
// 返回值:
// int32:可用的位置序号(从1开始)
func (this *TeamInfo) getUsableIndex() int32 {
	var i int32
	for i = 1; int(i) <= len(this.memberData); i++ {
		_, isExist := this.memberData[i]
		if isExist == false {
			return i
		}
	}

	return int32(len(this.memberData) + 1)
}

// 创建时间
func (this *TeamInfo) CreateTime() time.Time {
	return this.createTime
}

// 设置创建时间
func (this *TeamInfo) SetCreateTime(targetTime time.Time) {
	this.createTime = targetTime
}

// 模块Id
func (this *TeamInfo) ModuleId() int32 {
	return this.moduleId
}

// 获取翻牌信息
func (this *TeamInfo) FanPaiInfo() string {
	return this.fanPaiInfo
}

// 设置翻牌信息
func (this *TeamInfo) SetFanPaiInfo(fanPaiInfo string) {
	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.fanPaiInfo = fanPaiInfo
	this.lastHandleTime = time.Now().Local()
}

// 是否自动匹配
func (this *TeamInfo) IfAutoReady() bool {
	return this.ifAutoReady
}

// 设置是否自动匹配
func (this *TeamInfo) SetIfAutoReady(_ifAutoReady bool) {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.ifAutoReady = _ifAutoReady
}

// 是否挂机
func (this *TeamInfo) IsGuaji() bool {
	return this.isGuaji
}

// 设置是否挂机
func (this *TeamInfo) SetIsGuaji(_isGuajiStatus bool) {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.isGuaji = _isGuajiStatus
}

// 获取队伍宣言信息
func (this *TeamInfo) Slogan() string {
	return this.slogan
}

// 设置队伍宣言信息
func (this *TeamInfo) SetSlogan(slogan string) {
	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.slogan = slogan
	this.lastHandleTime = time.Now().Local()
}

// 最低战力要求
func (this *TeamInfo) MinFap() int64 {
	return this.minFap
}

// 获取队伍数据副本
func (this *TeamInfo) GetCopy() *TeamInfo {
	result := *this

	result.memberData = this.MemberDataCopy()

	return &result
}

// 获取是否在队伍推荐接口可见
func (this *TeamInfo) IfCanShow() bool {
	return this.ifCanShow
}

// 设置是否在队伍推荐接口可见
// _ifCanShow:是否可见
func (this *TeamInfo) SetIfCanShow(_ifCanShow bool) {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.ifCanShow = _ifCanShow
}

// 获取节点各个boss的推荐战力
func (this *TeamInfo) NodeFap() interface{} {
	return this.nodeFap
}

// 设置节点各个boss的推荐战力
// nodeFap:推荐的战力值
func (this *TeamInfo) SetNodeFap(nodeFap interface{}) {
	this.UpdateLastHandleTime()

	if isOk, prevStack, currStack := this.teamLocker.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.teamLocker.Unlock()

	this.nodeFap = nodeFap
}

// 创建队伍信息
// leader:队长信息
// _moduleId:所属模块
// _battleNodeId:战斗节点Id
// _minFap:最低战力要求
// _slogan:队伍宣言
// 返回值:
// *TeamInfo:战力值
func NewTeamInfo(_leader *TeamMember, _moduleId int32, _battleNodeId int32, _minFap int64, _slogan string) *TeamInfo {
	teamInfo := &TeamInfo{
		battleNodeId:    _battleNodeId,
		leader:          _leader,
		memberData:      make(map[int32]*TeamMember, 4),
		teamLocker:      syncUtil.NewRWLocker(),
		createTime:      time.Now().Local(),
		moduleId:        _moduleId,
		minFap:          _minFap,
		slogan:          _slogan,
		lastHandleTime:  time.Now().Local(),
		needBattleCount: 1,
		ifCanShow:       true,
		nodeFap:         make([]int64, 0),
	}

	// 把队长添加到队伍成员
	positionId := teamInfo.getUsableIndex()
	teamInfo.memberData[positionId] = _leader

	return teamInfo
}
